<?php
namespace app\client\controller\pay;
use think\db\Expression;
use Exception;

class HeeController extends \think\Controller {
  
  const URL_APPLYPAY  = 'https://Pay.Heepay.com/DirectPay/applypay.aspx';
  const URL_REFUND    = 'https://pay.Heepay.com/DirectPay/Refund.aspx';
  
  private function _MakeTradeNo() {
    $trno = MakeTradeNo();
    $host = $this->request->host();
    $flag = substr($host, 0, 1);
    $flag = $flag == false ? '' : $flag;
    $flag = strtoupper($flag);
    $trno = $flag.$trno;
    return $trno;
  }
  /**
   *  @brief  : 汇付宝H5支付
   *  @return : http://dev.heepay.com/index.php?s=/31&page_id=251
   *  @details: http://kk.zf.game654.cn/pay.hee/apply.html?XDEBUG_SESSION_START=1&UserID=28&GoodID=2&meta_option=%7B%22s%22%3A%22IOS%22%2C%22n%22%3A%22%E9%97%B2%E6%9C%89%E5%A8%B1%E4%B9%90%22%2C%22id%22%3A%22myxyyl%22%7D&KindID=0
   */
  public function ApplyAction() {
    
    $UserID = $this->request->param('UserID/d', 0); // 用户标识
    $GoodID = $this->request->param('GoodID/d', 0); // 商品数组下标, 按面值从小至大, 从0开始
    $KindID = $this->request->param('KindID/d', 0); // 对应小游戏, 0=大厅
    $Type   = $this->request->param('Type/d', 0); // 用哪个商品组
    $PayType= $this->request->param('PayType/d', 3); // 用哪个支付组
    $meta_option = $this->request->param('meta_option/s', '');
    
    if ($UserID <= 0 || $GoodID < 0 || $KindID < 0 || empty($meta_option) || $PayType < 0) {
      return abort(100, '业务参数输入有误');
    }

    $meta_option = iconv('UTF-8', 'GBK', $meta_option);
    $meta_option = base64_encode($meta_option);
    $meta_option = urlencode($meta_option);

    // 确定玩家
    $User = table('AccountsInfo', "rydb.accounts")->where(['UserID' => $UserID])->find();
    if (empty($User)) {
      return abort(102, "用户[{$UserID}]不存在");
    }
    
    // 确定商品
    $Goods = table('CardCoin', "rydb.websms")->where(['State' => 1, 'Type' => $Type, 'Channel' => $User['Channel'], 'PayType' => $PayType ,'KindID' => $KindID])->order(['RMB' => 'ASC'])->select();
    if (empty($Goods)) {
      return abort(103, '游戏商品未定义');
    }
    
    if (empty($Goods[$GoodID])) {
      return abort(104, '该商品不存在');
    }
    $Goods = $Goods[$GoodID];

    /// 确定订单 ///////////////////////////////////////////////////////////////
    $Price = sprintf('%.2f', $Goods['RMB']);
    $TradeNo  = $this->_MakeTradeNo();
    $HeePay = config('pay.HeePay');
    $notify_url = url('Notify', '', true, true);
    $return_url = url('Result', '', true, true);
    $timestamp = floor(microtime(true) * 1000);

    // 构造回传参数 "UserID,CardID,IP,KindID"
    $remark = [$UserID, $Goods['ID'], $this->request->ip(), $KindID];
    $remark = implode(',', $remark); // 减小remark长度, 不然会报错
    $param = [
      'version'         => 1,  // 必填  当前接口版本号1
      'agent_id'        => $HeePay['app_id'],  // 必填  商户编号 如1234567（中信银行商户编号：七位整数数字）
      'agent_bill_id'   => $TradeNo,  // 必填  商户系统内部的订单号（要保证唯一）。长度最长50字符
      'agent_bill_time' => date('YmdHis'),  // 必填  提交单据的时间yyyyMMddHHmmss 如：20100225102000该参数共计14位，当时不满14位时，在后面加0补足14位
      'pay_type'        => 30,  // 必填  支付类型30，（数据类型：int）
      'pay_amt'         => $Price,  // 必填  订单总金额 不可为空，单位：元
      'notify_url'      => $notify_url,  // 必填  异步通知地址,用户支付成功后会将支付结果发送到该页面,商户做后续的业务处理（该地址要外网可访问）。
      'return_url'      => $return_url,  // 必填  同步通知地址，支付成功后先跳转到该地址，该地址通常不作为逻辑处理,只作为信息展示（该地址要外网可访问）。
      'user_ip'         => $this->request->ip(),  // 必填  用户所在客户端的真实ip，否则无法支付。
      'bank_card_type'  => -1,  // 必填  银行类型：未知=-1;储蓄卡=0;信用卡=1
      'remark'          => $remark,  // 必填  自定义参数
      'goods_name'      => urlencode('游戏充值'),  // 必填  商品名称, 长度最长50字符，不能为空。
      'scene'           => 'h5',  // 必填  支付方式，h5表示h5，qr表示扫码（如支付类型为扫码，payment_mode传UnifiedOrder返回二维码url），jsapi表示公众号(值均为小写)
      'meta_option'     => $meta_option,  // 必填  {“s”:”WAP”,”n”:””,”id”:””}（不参加签名）
      // 'goods_num'       => 1,
      // 'goods_note'      => 'goods_note',  // '1元=100欢乐豆',  // 选填  支付说明，长度50字符（不参加签名）
      // 'payment_mode'    => 'cashier',  // 必填  收银台=cashier
      // 'timestamp'       => $timestamp,  // 选填  时间戳，传了订单有效时间上下1min，从1970年1月1日0时到现在的毫秒数，传了参与签名，签名位置在key前面。
      // 'sign'            => '',  // 必填  MD5签名结果
    ];

    $sign = '';
    $sign = "{$sign}version={$param['version']}";
    $sign = "{$sign}&agent_id={$param['agent_id']}";
    $sign = "{$sign}&agent_bill_id={$param['agent_bill_id']}";
    $sign = "{$sign}&agent_bill_time={$param['agent_bill_time']}";
    $sign = "{$sign}&pay_type={$param['pay_type']}";
    $sign = "{$sign}&pay_amt={$param['pay_amt']}";
    $sign = "{$sign}&notify_url={$param['notify_url']}";
    $sign = "{$sign}&return_url={$param['return_url']}";
    $sign = "{$sign}&user_ip={$param['user_ip']}";
    $sign = "{$sign}&bank_card_type={$param['bank_card_type']}";
    $sign = "{$sign}&remark={$param['remark']}";
    $sign = "{$sign}&key={$HeePay['app_key']}";
    $sign = md5($sign);
    $param['sign'] = $sign;
    trace($param);
    $retn = file_get_contents(self::URL_APPLYPAY.'?'.http_build_query($param));
    trace($retn);
    $retn = self::XML2Array($retn);
    if (!isset($retn['redirectUrl'])) {
      abort(110, "下单失败[{$retn['ret_code']}][{$retn['ret_msg']}]");
    }
    $this->redirect($retn['redirectUrl']);
  }

  /**
   *  @brief  : 汇付宝H5支付异步通知
   *  @return : string('error' || 'ok')
   *  @details:
   */
  public function NotifyAction() {

    trace(__METHOD__);
    $data = $this->request->param();
    trace($data);

    if (empty($data)) {
      echo('error');
      return;
    }
    /// 验证签名是否合法 ///////////////////////////////////////////////////////
    $HeePay = config('pay.HeePay');
    $sign = '';
    $sign = "{$sign}result={$data['result']}";
    $sign = "{$sign}&agent_id={$data['agent_id']}";
    $sign = "{$sign}&jnet_bill_no={$data['jnet_bill_no']}";
    $sign = "{$sign}&agent_bill_id={$data['agent_bill_id']}";
    $sign = "{$sign}&pay_type={$data['pay_type']}";
    $sign = "{$sign}&pay_amt={$data['pay_amt']}";
    $sign = "{$sign}&remark={$data['remark']}";
    $sign = "{$sign}&key={$HeePay['app_key']}";
    $sign = md5($sign);
    
    trace("输入sign={$data['sign']}");
    trace("计算sign={$sign}");

    if ($sign != $data['sign']) {
      trace('验签失败');
      echo('error');
      return;
    }
    trace('验签成功');

    // 解析回传参数 "UserID,CardID,IP,KindID"
    $params = empty($data['remark']) ? '' : $data['remark'];
    $params = explode(',', $params);
    $params = empty($params) ? [] : $params;
    
    $UserID   = empty($params[0]) ? 0 : $params[0] * 1;
    $CardID   = empty($params[1]) ? 0 : $params[1] * 1;
    $ClientIP = empty($params[2]) ? '' : $params[2];
    $KindID   = empty($params[3]) ? 0 : $params[3] * 1; // 从下单请求中传入

    if ($CardID < 0 || $UserID <= 0 || $KindID < 0) {
      trace('回传参数丢失或无效');
      echo('error');
      return;
    }
    
    if ($HeePay['app_id'] != $data['agent_id']) {
      trace("app_id验证失败[{$HeePay['app_id']}]!=[{$data['agent_id']}]");
      echo('error');
      return;
    }
    
    try {
      $eax = ChargeUpdate(2, $UserID, $CardID, $ClientIP, $KindID, $data['agent_bill_id'], $data['jnet_bill_no'], $data['pay_amt']);
      echo('ok');
    } catch (Exception $e) {
      $errno = $e->getCode();
      $error = $e->getMessage();
      trace(['errno' => $errno, 'error' => $error]);
      echo('error');
    }
    return;
  }
  /**
   *  @brief  : 汇付宝H5支付同步跳转
   *  @return : page
   *  @details: 
   */
  public function ResultAction() {
    trace(__METHOD__);
    trace($this->request->param());
    echo('Thank you!');
  }
  /**
   *  @brief  : 汇付宝退款
   *  @return : page
   *  @details: php index.php client/pay.hee/Refund
   */
  public function RefundAction() {
    var_dump(__METHOD__);

    $HeePay = config('pay.HeePay');
    $param = [
      'version'         => 1,
      'agent_id'        => $HeePay['app_id'],
      'agent_bill_id'   => '201904131649336282',
      // 'refund_details'  => '',
      'notify_url'      => url('Result', '', true, true),
    ];
    
    $sign = '';
    $sign = "{$sign}agent_bill_id={$param['agent_bill_id']}";
    $sign = "{$sign}&agent_id={$param['agent_id']}";
    $sign = "{$sign}&key={$HeePay['app_key']}";
    $sign = "{$sign}&notify_url={$param['notify_url']}";
    $sign = "{$sign}&version={$param['version']}";
    $sign = md5($sign);
    $param['sign'] = $sign;
    
    print_r($param);
    
    $retn = file_get_contents(self::URL_REFUND.'?'.http_build_query($param));
    print_r($retn);
    
  }
  /**
   *  @brief  : xml字符串转array
   *  @param [in] $xml : 欲转换xml字符串
   *  @return : array
   *  @details: 
   */
  public static function XML2Array($xml) {
    $arr = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
    $arr = json_encode($arr, JSON_UNESCAPED_UNICODE);
    $arr = json_decode($arr, true);
    return $arr;
  }
}
